/* 
 * File:   main.c
 * Author: mobil
 *
 * Created on den 15 september 2013, 20:34
 */
#include <xc.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

#define SYS_FREQ        4000000L
#define FCY             SYS_FREQ/4
#define _XTAL_FREQ      4000000

#pragma config WDTE=OFF, MCLRE=OFF, CP=OFF, FOSC=INTRCIO

int pulse_length = 0;
int blink_length = 0;
int adc_value = 0;
float voltage = 0;
bool LOW_VOLTAGE_ALARM = true;

enum input_state {THR, GEAR, AUX1};
enum input_state input;

enum power_state {OFF, ON};
enum power_state power = OFF;

enum color_state {COLOR, WHITE};
enum color_state color = COLOR;

void RestartTimer0(void);
void ReadTimer0(void);
void Delay_Blink(int);
float Get_Voltage(void);


/*
 * Blink RGB
 */
int main(int argc, char** argv) {

    GPIO = 0x00;
    TRISIO = 0x38;
    //AD: ADCS = FOSC/16
    ANSEL = 0b01011000;
    //AD: left justified, VCFG = VDD, AN3, conversion off, converter operational
    ADCON0 = 0b00001101;
    //Comparator off
    CMCON = 0x07;
    //Enable TMR0 CLKOUT, enable prescaler 1:16
    OPTION_REG = 0b11010011;
    //Enable interrupt-on-change for GPIO5
    IOC5 = 1;
    //Enable interrupt-on-change for GPIO4
    IOC4 = 1;
    //Enable interrupt-on-change for GPIO3
    IOC3 = 1;
    //Enable interrupt-on-change
    GPIE = 1;
    //Enable global interrupt enable it
    GIE = 1;

    while(1)
    {
        voltage = Get_Voltage();
        if (voltage < 10.5)
        {
            LOW_VOLTAGE_ALARM = true;
        }
        else
        {
            LOW_VOLTAGE_ALARM = false;
        }

        // If low voltage blink even if power = off.
        if ((power == ON) | LOW_VOLTAGE_ALARM)
        {
            //if (color == COLOR)
            //{
                //GP0 = 0;
                GP1 = 0;
                GP2 = 1; //GREEN (or RED) depending on arm
            //}
            /*else if (color == WHITE)
            {
                GP0 = 1;
                GP1 = 1;
                GP2 = 1;
            }*/
        }

        __delay_ms(100);

        //If low voltage, light up red instead of no lights
        if (LOW_VOLTAGE_ALARM)
        {
            GP1 = 0;
            GP2 = 0;

            Delay_Blink((blink_length-150)/2);
            GP1 = 1; //light upp red
            __delay_ms(100);
            GP1 = 0;
            Delay_Blink((blink_length-150)/2);
        }
        else if (blink_length > 150)
        {
            //GP0 = 0;
            GP1 = 0;
            GP2 = 0;

            Delay_Blink((blink_length-150));
        }
    }

    return (EXIT_SUCCESS);
}

void interrupt Measure_PWM(void)
{
    //check if the interrupt is caused by a GPIO change
    if(GPIF == 1)
    {
        if (GP5 == 1)
        {
            //If start of pulse, restart timer.
            //OK to use same timer for all signals as they never overlap
            RestartTimer0();
            input = THR;
        }
        else if (GP3 == 1)
        {
            //If start of pulse, restart timer.
            RestartTimer0();
            input = GEAR;
        }
        /* Sacrificing AUX1 channel to allow voltage measurement on AN3 (GP4) instead.
        else if (GP3 == 1)
        {
            //If start of pulse, restart timer.
            RestartTimer0();
            input = AUX1;
        }*/
        else
        {
            //If end of pulse, read pulse length.
            ReadTimer0();
        }
        GPIF = 0;
    }
}

void RestartTimer0(void)
{
    TMR0 = 0x00;
}

void ReadTimer0(void)
{
    // PWM pulse length in ms
    pulse_length = TMR0 * 16;
    switch (input)
    {
        case THR:
            // Calculate blink length between 0 and 1000 ms.
            // Pulse lenght = 1000 - 2000 us ->
            // blink length  = 0 - 1000 ms
            blink_length = (2000 - pulse_length);
            break;
        case GEAR:
            //Gear -> Light on off
            if (pulse_length <= 1500)
            {
                power = OFF;
            }
            else if (pulse_length > 1500)
            {
                power = ON;
            }
            break;
            /*
        case AUX1:
            //Aux1 -> Light on off
            if (pulse_length <= 1500)
            {
                color = COLOR;
            }
            else if (pulse_length > 1500)
            {
                color = WHITE;
            }
            break;
              */
    }
}

void Delay_Blink(int delay)
{
    int i;
    for (i = 0; i < delay; i++)
    {
        __delay_ms(1);
    }
}

float Get_Voltage(void)
{
    GO = 1; 		//Start Conversion
    while(GO){}             //Wait for conversion complete
    adc_value = ADRESH; //Use only high-bits (256 levels)
    return adc_value*3*5/256;                                                            //Display ADC value at GPIO port
}